<?php
 class PayPalComponent extends Object {
 	//credentials
	var $user;
	var $vendor;
	var $partner;
	var $password;
	
	var $connection;
	var $transaction;	
	var $cc;
	var $buyer;
	var $response;

	function startup(&$controller){
	// required fields 
	/*
		* TRXTYPE 
		* TENDER 
		* PARTNER 
		* VENDOR 
		* USER 
		* PWD 		
		---------
		* ACCT 
		* AMT 
		* EXPDATE 
	*/


	// credentials -- pulled from vendor
		App::import('Vendor', 'vcom_creds', array('file' => 'Vcom'.DS.'vcom_creds.php'));
		$vcomCreds = new VcomCreds();

		$this->user = $this->__aes_128_decrypt($vcomCreds->user, Configure::read('Security.enckey'));
		$this->vendor = $this->__aes_128_decrypt($vcomCreds->vendor, Configure::read('Security.enckey'));
		$this->partner = $this->__aes_128_decrypt($vcomCreds->partner, Configure::read('Security.enckey'));
		$this->password = $this->__aes_128_decrypt($vcomCreds->password, Configure::read('Security.enckey')); // PWD

	// connection info
		if(Configure::read('Paypal.live')) :
			$this->connection['url'] = 'https://payflowpro.paypal.com';
		else:
			$this->connection['url'] = 'https://pilot-payflowpro.paypal.com';
		endif;
		$this->connection['port'] = 443;
		$this->connection['tender'] = 'C'; // for credit card transactions
		$this->connection['transactionType'] = 'S'; // TRXTYPE, must perform authorization and then a 'D' delayed capture
		$this->connection['verbosity'] = 'MEDIUM';
		$this->connection['time_out'] = '30'; //TIMEOUT

	// build order info
		$this->transaction = array('total' => '' //AMT
						    ,'currency' => 'USD'
						    ,'comment1' => ''
						    ,'comment2' => ''
						    ,'order_number' => '' //CUSTREF
						    ,'end_time' => '' //ENDTIME
						    ,'start_time' => '' //STARTTIME
						    ,'origid' => ''
						    ,'auth_code' => ''
						    );

	// build credit card
		$this->cc = array('card_number' => '' //ACCT
						 ,'CVV2' => ''
						 ,'expiration_date' => '' //EXPDATE
						 );

	// build buyer	
		$this->buyer = array('first_name' => '' //FIRSTNAME, need to combine first and last
							,'last_name' => '' //LASTNAME
							,'address1' => '' //STREET
							,'city' => ''
							,'state' => ''
							,'zip' => ''
							,'country' => ''
							,'email' => ''
							);
	//
		$this->response = array('pnref' => ''
							  ,'ppref' => ''
							  ,'result' => ''
							  ,'cvv2_match' => '' //CVV2MATCH
							  ,'response_message' => '' //RESPMSG
							  ,'avs_addr' => '' //AVSADDR
							  ,'avs_zip' => '' //AVSZIP
							  ,'iavs' => ''
							  ,'proc_avs' => '' //PROCAVS
							  ,'proc_cvv2' => '' //PROCCVV2
							  ,'payment_type' => '' //PAYMENTTYPE
							  ,'correlation_id' => '' //CORRELATIONID
							  ,'bal_amt' => '' //BALAMT
							  ,'amex_id' => '' //AMEXID
							  ,'amex_pos_data' => ''	//AMEXPOSDATA		
							  ,'host_code' => '' //HOSTCODE
							  ,'response_text' => '' //RESPTEXT
							  ,'date_to_settle' => '' //DATE_TO_SETTLE
							  );		

	} // startup
	
	function transact() {
		
		$post = $this->__buildPost();
		$user_agent = $_SERVER['HTTP_USER_AGENT'];

		// Here's your custom headers; adjust appropriately for your setup:
		$headers[] = "Content-Type: text/namevalue"; //or text/xml if using XMLPay.
		$headers[] = "Content-Length : " . strlen ($post);  // Length of data to be passed 
		// Here I set the server timeout value to 45, but notice below in the cURL section, I set the timeout
		// for cURL to 90 seconds.  You want to make sure the server timeout is less, then the connection.
		$headers[] = "X-VPS-Timeout: 45";
		$headers[] = "X-VPS-Request-ID:" . $this->transaction['order_number'];


		// Optional Headers.  If used adjust as necessary.
		//$headers[] = "X-VPS-VIT-OS-Name: Linux";                  // Name of your OS
		//$headers[] = "X-VPS-VIT-OS-Version: RHEL 4";          // OS Version
		//$headers[] = "X-VPS-VIT-Client-Type: PHP/cURL";          // What you are using
		//$headers[] = "X-VPS-VIT-Client-Version: 0.01";          // For your info
		//$headers[] = "X-VPS-VIT-Client-Architecture: x86";          // For your info
		//$headers[] = "X-VPS-VIT-Integration-Product: PHPv4::cURL";  // For your info, would populate with application name
		//$headers[] = "X-VPS-VIT-Integration-Version: 0.01";         // Application version

		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $this->connection['url']);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
		curl_setopt($ch, CURLOPT_HEADER, 1);                // tells curl to include headers in response
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);        // return into a variable
		curl_setopt($ch, CURLOPT_TIMEOUT, 90);              // times out after 90 secs
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);        // this line makes it work under https
		curl_setopt($ch, CURLOPT_POSTFIELDS, $post);        //adding POST data
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,  2);       //verifies ssl certificate
		curl_setopt($ch, CURLOPT_FORBID_REUSE, TRUE);       //forces closure of connection when done
		curl_setopt($ch, CURLOPT_POST, 1); 									//data sent as POST

		//debug($this);		
	/*
		//echo $data;
		echo '<br><br>';
		// Try to submit the transaction up to 3 times with 5 second delay.  This can be used
		// in case of network issues.  The idea here is since you are posting via HTTPS there
		// could be general network issues, so try a few times before you tell customer there
		// is an issue.	
		
	  echo '<h4>Processing order ... please wait</h4>';
	  */
	  
		$i=1;
		while ($i++ <= 3) {
			$result = curl_exec($ch);
			$headers = curl_getinfo($ch);
			//print_r($headers);
			//echo '<br>';
			//print_r($result);
			//echo '<br>';
			if ($headers['http_code'] != 200) {
				sleep(5);  // Let's wait 5 seconds to see if its a temporary network issue.
			}
			else if ($headers['http_code'] == 200) {
				// we got a good response, drop out of loop.
				break;
			}
		}
		
		// In this example I am looking for a 200 response from the server prior to continuing with
		// processing the order.  You can use this or other methods to validate a response from the
		// server and/or timeout issues due to network.
		if ($headers['http_code'] != 200) {
			echo '<h2>General Error!</h2>';
			echo '<h3>Unable to receive response from PayPal server.</h3><p>';
			echo '<h4>Verify host URL of '.$submiturl.' and check for firewall/proxy issues.</h4>';
			curl_close($ch);
			exit;
		}
		curl_close($ch);
		$result = strstr($result, "RESULT");
		// echo $result;
		// prepare responses into array
		$proArray = array();
		while(strlen($result)){
			// name
			$keypos= strpos($result,'=');
			$keyval = substr($result,0,$keypos);
			// value
			$valuepos = strpos($result,'&') ? strpos($result,'&'): strlen($result);
			$valval = substr($result,$keypos+1,$valuepos-$keypos-1);
			// decoding the respose
			$proArray[$keyval] = $valval;
			$result = substr($result,$valuepos+1,strlen($result));
		}
	
		if(isset($proArray['RESULT'])) :
			$this->response['result'] = $proArray['RESULT'];		
		endif;	
		if(isset($proArray['PNREF'])) :
			$this->response['pnref'] = $proArray['PNREF'];		
		endif;		
		if(isset($proArray['RESPMSG'])) :
			$this->response['response_message'] = $proArray['RESPMSG'];				
		endif;		
		if(isset($proArray['AVSADDR'])) :
			$this->response['avs_addr'] = $proArray['AVSADDR'];		
		endif;
		if(isset($proArray['AVSZIP'])) :
			$this->response['avs_zip'] = $proArray['AVSZIP'];				
		endif;
		if(isset($proArray['HOSTCODE'])) :
			$this->response['host_code'] = $proArray['HOSTCODE'];				
		endif;		
		if(isset($proArray['RESPTEXT'])) :
			$this->response['response_text'] = $proArray['RESPTEXT'];				
		endif;		
		if(isset($proArray['PROCAVS'])) :
			$this->response['proc_avs'] = $proArray['PROCAVS'];		
		endif;		
		if(isset($proArray['DATE_TO_SETTLE'])) :
			$this->response['date_to_settle'] = $proArray['DATE_TO_SETTLE'];
		endif;	
		if(isset($proArray['IAVS'])) :
			$this->response['iavs'] = $proArray['IAVS'];		
		endif;
		if(isset($proArray['DUPLICATE'])) :
			$this->response['duplicate'] = $proArray['DUPLICATE'];
		endif;
		
		if(isset($proArray['PNREF'])) :
			$this->transaction['origid'] = $proArray['PNREF'];				
		endif;
		if(isset($proArray['AUTHCODE'])) :
			$this->transaction['auth_code'] = $proArray['AUTHCODE'];			
		endif;		
		
		if(isset($this->response['duplicate']) && ($this->response['duplicate'] == 1)) :
			//trigger_error('Duplicated transaction.');
			return false;
		endif;
		
		if($this->response['result'] != 0) :
			//trigger_error('Transaction failed: #'.$this->response['result'].' -- '.$this->response['response_message']);
			return false;
		endif;		
		
		return true;
	} //transact
	
	// builds the post body
	function __buildPost() {
		
	
	//required fields, or fields that will always have data
		$post = 'USER='.$this->user.'&VENDOR='.$this->vendor.'&PARTNER='.$this->partner.'&PWD='.$this->password.'&TENDER='.$this->connection['tender'].'&TRXTYPE='.$this->connection['transactionType'].'&VERBOSITY='.$this->connection['verbosity'].'&TIMEOUT='.$this->connection['time_out'].'&AMT='.$this->transaction['total'].'&CURRENCY='.$this->transaction['currency'];

	//optional fields need to be check to see if they exist	
		if($this->transaction['comment1']) :
			$post .= '&COMMENT1='.$this->transaction['comment1'];
		endif;
		if($this->transaction['comment2']) :
			$post .= '&COMMENT2='.$this->transaction['comment2'];
		endif;
		if($this->transaction['order_number']) :
			$post .= '&CUSTREF='.$this->transaction['order_number'];
		endif;
		if($this->transaction['end_time']) :
			$post .= '&ENDTIME='.$this->transaction['end_time'];
		endif;
		if($this->transaction['start_time']) :
			$post .= '&STARTTIME='.$this->transaction['start_time'];
		endif;
		if($this->transaction['origid']) :
			$post .= '&ORIGID='.$this->transaction['origid'];
		endif;
		if($this->transaction['auth_code']) :
			$post .= '&AUTHCODE='.$this->transaction['auth_code'];
		endif;
		if($this->cc['card_number']) :
			$post .= '&ACCT='.$this->cc['card_number'];
		endif;
		if($this->cc['CVV2']) :
			$post .= '&CVV2='.$this->cc['CVV2'];
		endif;
		if($this->cc['expiration_date']) :
			$post .= '&EXPDATE='.$this->cc['expiration_date'];
		endif;
		if($this->buyer['first_name']) :
			$post .= '&NAME='.$this->buyer['first_name'].' '.$this->buyer['last_name'];
		endif;
		if($this->buyer['address1']) :
			$post .= '&STREET='.$this->buyer['address1'];
		endif;
		if($this->buyer['city']) :
			$post .= '&CITY='.$this->buyer['city'];
		endif;
		if($this->buyer['state']) :
			$post .= '&STATE='.$this->buyer['state'];
		endif;
		if($this->buyer['zip']) :
			$post .= '&ZIP='.$this->buyer['zip'];
		endif;
		if($this->buyer['country']) :
			$post .= '&COUNTRY='.$this->buyer['country'];
		endif;	
		if($this->buyer['email']) :
			$post .= '&EMAIL='.$this->buyer['email'];
		endif;		
	
		//print_r($post);
	
		return trim($post);
	} // buildPost

	function __aes_128_decrypt($encrypted_text,$password) {
		App::import('Vendor', 'AES', array('file' => 'phpAES'.DS.'AES.class.php'));
		$aes = new AES(str_pad($password, 16, chr(0)));
		$cpt = $aes->decrypt(pack("H*", $encrypted_text));
		return $cpt;

		/*$size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
		$iv = mcrypt_create_iv($size, MCRYPT_DEV_URANDOM);

		return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $password, pack("H*", $encrypted_text), MCRYPT_MODE_ECB, $iv);*/
	} // End of function 
}
?>